/**
 * @file Door_control_dll.h
 * @mainpage Door_control_dll
 * @par Description:
 * dll to work with door controller
 * - controls actuator
 * - controls relay to break modem power
 * - reads state of reeds
 *
 * @par Here is example:
 * - door_control_init();
 * - door_control_dev_if_mode(int mode);	// int mode = 2
 * - door_control_ser_set_name(const char *ser_port_name); // char[] ser_port_name = "//./COM1"
 * - door_control_dev_open();
 * - door_control_lock_set(int state);;	// int state = 1 - lock open
 * - cout << "inputs : " << hex << door_control_inps_get() << endl;
 * - door_control_lock_set(int state);;	// int state = 1 - lock close
 * - cout << "inputs : " << hex << door_control_inps_get() << endl;
 * - door_control_modem_reset();
 * - cout << "inputs : " << door_control_inps_get() << endl;
 * - door_control_finish();
 *
 *  Created on: 04.07.2012
 *     @Author: aska
 */
#ifndef DOOR_CONTROL_DLL_H
#define DOOR_CONTROL_DLL_H
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string>
#include <list>
#include <iterator>
#include <vector>
#include <iostream>
#include <fstream>

using namespace std;
//#include <boost/thread/thread.hpp>
//#include <boost/thread/mutex.hpp>

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/foreach.hpp>

//#include <boost/thread/locks.hpp>
//#include <wininet.h>
//#pragma comment(lib,"Wininet.lib")
//#include "curl"
//#include <winsock2.h>
#include "ftdi2xx.h"
#include "ping.h"

typedef list<string> LISTSTR;
const int CMD_NO_COMMAND = 0;
const int CMD_QUIT = 1;

#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) BOOL WINAPI __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
/**\brief Initialization
 *
 * should be called first
 *
 * int door_control_init(void);
 *
 * @return
 * - 0 - OK
 * - 1 - failed
 */
__declspec(dllexport) int __stdcall door_control_init(void);
/**\brief Set interface mode
 *
 * select device interface mode: Virtual Communication Port or D2XX interface
 *
 * @param[in] int mode
 * - 1 - VCP mode (serial port)
 * - 2 - D2XX mode
 *
 * @return
 * - 0 - OK
 * - 1 - incorrect mode
 */
__declspec(dllexport) int __stdcall door_control_dev_if_mode(int mode);

__declspec(dllexport) int __stdcall set_read_buff_after_writing(int inp_val);
/**\brief Set serial port name
 *
 * @param[in] const char *ser_port_name - name of serial port
 *
 * @return
 * - 0 - OK
 */
__declspec(dllexport) int __stdcall door_control_ser_set_name(const char *ser_port_name);
/**\brief Set serial port name by port number
 *
 * @param[in] int port_no - number of serial port
 *
 * @return
 * - 0 - OK
 */
__declspec(dllexport) int __stdcall door_control_ser_set_num(int port_no);
/**\brief Opens serial port or FTDI device and checks device type
 *
 * port name has to be set before by door_control_ser_set_name(const char *s),
 * mode has to be selected if D2XX used,
 * see door_control_dev_if_mode(int mode)
 *
 * @return
 * <ul>
 * <li> 0 - OK</li>
 * <li> 7 - incorrect dev_interface_mode</li>
 * </ul>
 * if mode is serial
 * <ul>
 * <li> 1 - failed CreateFile</li>
 * <li> 2 - failed SetCommState</li>
 * <li> 3 - failed device type check</li>
 * </ul>
 * if mode is d2xx
 * <ul>
 * <li> 1 - incorrect serial port name</li>
 * <li> 2 - unable to get FTDI info</li>
 * <li> 3 - unable to get corresponding serial port nnumber</li>
 * <li> 4 - unable to get handle</li>
 * <li> 5 - FTDI devices not found</li>
 * </ul>
 * any mode
 * <ul>
 * <li> bit 4 is set - unable to read port</li>
 * <li> bit 5 is set - incorrect returned message</li>
 * </ul>
 */
__declspec(dllexport) int __stdcall door_control_dev_open(void);
/**\brief Get FTDI driver version
 *
 * device has to be opened before this function can be called
 * see door_control_dev_open();
 *
 * A version number consists of major, minor and build version numbers contained in a 4-byte field (unsigned long).
 * Byte0 (least significant) holds the build version,
 * Byte1 holds the minor version,
 * Byte2 holds the major version.
 * Byte3 is currently set to zero.
 * For example, driver version "2.04.06" is represented as 0x00020406.
 *
 * @param[out] unsigned int * Pointer to the driver version number
 *
 * @return
 * - 0 - OK
 * - 1 - device not opened
 * - -ft_status - unable to get driver version
 *
 */
__declspec(dllexport) int __stdcall door_control_ft_get_driver_version(unsigned int* ft_drv_ver);
/**\brief Get D2XX library version
 *
 * A version number consists of major, minor and build version numbers
 * contained in a 4-byte field (unsigned long).
 * Byte0 (least significant) holds the build version,
 * Byte1 holds the minor version, and
 * Byte2 holds the major version.
 * Byte3 is currently set to zero.
 * For example, D2XX DLL version "3.01.15" is represented as 0x00030115.
 *
 * @param[out] unsigned int * Pointer to the library version number
 *
 * @return
 * - 0 - OK
 * - 1 - library not initialized
 * - -ft_status - unable to get driver version
 *
 */
__declspec(dllexport) int __stdcall door_control_ft_get_library_version(unsigned int* ft_lib_ver);
/**\brief Opens serial port
 *
 * port name has to be be set before by door_control_ser_set_name(const char *s);
 *
 * @return
 * - 0 - OK
 * - 1 - failed CreateFile
 * - 2 - failed SetCommState
 */
__declspec(dllexport) int __stdcall door_control_ser_open(void);
/**\brief Set board version
 *
 * port has to be opened, board version, 0...255
 *
 *
 * @param[in] char board_version - board version
 *
 * @return
 * - 0 - OK
 * - bit 0 is set - unable to write into port
 * - bit 1 is set - unable to read port
 * - bit 2 is set - incorrect returned message
 */
__declspec(dllexport) int __stdcall door_control_set_brd_ver(char board_version);
/**\brief Returns board version
 *
 * port has to be opened
 *
 * @param[out] char * board_version - board version
 *
 * @return
 * - 0 - OK
 * - bit 0 is set - unable to write into port
 * - bit 1 is set - unable to read port
 * - bit 2 is set - incorrect returned message
 */
__declspec(dllexport) int __stdcall door_control_get_brd_ver(char * board_version);
/**\brief Set serial No
 *
 * port has to be opened, serial number is 4-bytes string
 *
 * example:
 *  1234
 *
 * @param[in] char * buf - serial number
 *
 * @return
 * - 0 - OK
 * - bit 0 is set - unable to write into port
 * - bit 1 is set - unable to read port
 * - bit 2 is set - incorrect returned message
 */
__declspec(dllexport) int __stdcall door_control_set_ser_no(char * buf);
/**\brief Returns serial No
 *
 * port as to be opened
 *
 * example:
 * 1234
 *
 * @param[in] char * buf - input buffer, 4 is enough
 * @param[in] int buf_len - size of buf
 *
 * @return
 * - 0 - OK
 * - bit 0 is set - unable to write into port
 * - bit 1 is set - unable to read port
 * - bit 2 is set - incorrect returned message
 */
__declspec(dllexport) int __stdcall door_control_get_ser_no(char * buf, int buf_len);
/**\brief Returns firmware version
 *
 * port has to be opened
 *
 * format:
 *  fw @type door_control @ver 01_ed_01 @date 2012_07_26_01
 *  here
 *  - door_control - type of device
 *  - 01_ed_01 - firmware version
 *  - 2012_07_26_01 - compilation date
 *
 * @param[in] char * buf - input buffer, 63 is enough
 * @param[in] int buf_len - size of buf
 *
 * @return
 * - 0 - OK
 * - bit 0 is set - unable to write into port
 * - bit 1 is set - unable to read port
 * - bit 2 is set - incorrect returned message
 */
__declspec(dllexport) int __stdcall door_control_get_fwv(char * buf, int buf_len);
__declspec(dllexport) int __stdcall door_control_ser_set_baud(int baud);
__declspec(dllexport) int __stdcall door_control_ser_get_baud(void);
__declspec(dllexport) int __stdcall door_control_ser_read_buf(char * buf, int * n_recv, int size);
__declspec(dllexport) int __stdcall door_control_leds_set(int led_No, int led_state);
__declspec(dllexport) int __stdcall door_control_get_sum(int a, int b, int * sum);
/**\brief Opens or closes the lock
 *
 * @param[in] int state
 * - 0 to close
 * - 1 to open
 * @return
 * - 0 - OK
 * - 1 - failed WriteFile
 * - 2 - unable to read acknowledge
 * - 4 - incorrect acknowledge
 */
__declspec(dllexport) int __stdcall door_control_lock_set(int state);
/**\brief Get state of the inputs
 *
 * @return
 * - 0x00...0x0F - bits 0...3 are set to 1 if inputs 1...4 are opened, no contact, 0 if closed
 * - 0xA0 - failed WriteFile to serial
 * - 0xB0 - incorrect reply from controller
 */
__declspec(dllexport) int __stdcall door_control_inps_get(void);
/**\brief Reset modem
 *
 * @return
 * - 0 - OK
 * - 1 - failed WriteFile
 * - 2 - unable to read acknowledge
 * - 4 - incorrect acknowledge
 */
__declspec(dllexport) int __stdcall door_control_modem_reset(void);
__declspec(dllexport) int __stdcall door_control_ser_close(void);
/**\brief Finalization
 *
 * close port and free resources
 *
 * @return
 * - 0
 */
__declspec(dllexport) int __stdcall door_control_finish(void);

__declspec(dllexport) int __stdcall door_control_d2xx_dll_open(void);

/**\brief send ping
 *
 *
 * int send_ping(char * ip_addr);
 *
 * @return
 * - 0 - OK
 * - 1 - failed
 */
__declspec(dllexport) int __stdcall send_ping(char * ip_addr);
__declspec(dllexport) int __stdcall ping_start(void);
__declspec(dllexport) int __stdcall ping_stop(void);
__declspec(dllexport) int __stdcall ping_addr_add(char * ip_addr);

#ifdef __cplusplus
}
#endif

extern HINSTANCE dll_handle;
class door_control_device {
private:
	// variables to store serial port data
	DCB dcb_curr, dcb_prev;	// serial port structures for current and previous states
	COMMTIMEOUTS CommTimeOuts_curr, CommTimeOuts_prev;
	//
	int read_buff_after_writing;	// 1 - to read all data from serial after writing
public:
	int baud;	// Serial port baudrate
	HANDLE hPort;	// Serial port file hadle
	char ser_port_name[32];	// Serial port name
	int serial_is_opened;
	boost::interprocess::interprocess_mutex ser_port_mutex;
	FT_HANDLE ft_handle;	// handler for ftdi device
	FT_STATUS ft_status;	// variable to store returned value from ftdi functions
	unsigned short ft_LocId;
	HMODULE h_d2xx_dll;
	int d2xx_dll_is_loaded;	// 1 - dll is loaded, 0 - dll not loaded
	int d2xx_opened;
	int ft_handle_opened;
	int dev_interface_mode; // 1 - VCP mode, 2 - d2xx mode
	char fwv_str[127];	// Door_controller firmware version stored here
	char inps_state_prev;	// Inputs previous state. Used for logging changes of inputs only
	char inps_state_pres;	// Inputs current state
	char lock_state_pres;	// Lock current state
	char lock_state_prev;	// Lock previous state
	unsigned char tries_n;	// How many times to retry to perform command
	char log_file_name[255];	// Log file name
	char module_file_path[255];
	FILE * log_file_ptr;	// Log file pointer
	int log_file_year_day_prev;		// Log file previous day since January 1, for logging one file per day
	int log_file_year_day_pres;		// Log file current day since January 1
	int dbg_inps_r_counter;			// Debug, number of calling function inps_r
	int log_add_str(char * log_str);	// Function to write log string. Adds data in the beginning an and CR in the end of string.
	door_control_device(void);
	int read_params(void);
	int set_read_buff_after_writing(int inp_val);
	int open_ser(void);	// open serial port
	int open_d2xx_dll(void);	//load ftd2xx dll, return 0 if successfull, -1 if error
	int open_d2xx(void);
	int ft_get_driver_version(unsigned int* ft_driver_ver);
	int ft_get_library_version(unsigned int* ft_library_ver);
	int set_brd_ver(char board_version);
	int get_brd_ver(char * board_version);
	int set_ser_no(char * buf);
	int get_ser_no(char * buf);
	int get_fwv(char * buf);
	int set_baud(int inp_baud);
	int get_baud(void);
	int write_strz(char * buf);
	int read_buf(char * buf, int * n_recv, int size);
	int purge_buf(void);
	int conn_repair(void);
	int led_set(int led_No, int led_state);
	int get_sum(int a, int b, int * sum);
	int lock_set(int state);
	int relay_4_set(int state);
	int inps_get(void);
	int modem_reset(void);
	int ping_addr(char * ping_addr, int * ping_result);
	int ping_ctrl(int set_state);
	void * ping_proc(void *threadid);
	static void ping_thread();
	int ping_proc_work();
	//door_control_device * door_control_device_inst;
	//pinger pinger_inst;
	int ping_result;
	int ping_skipped;
	int ping_is_running;
	int ping_period_online;
	int ping_period_offline;
	int ping_timeout;
	int ping_delay_after_reset;
	bool ping_to_start;
	list<string> ping_addr_list;
	char ping_addr_char[32];
	enum commands {no_command, quit};
	enum commands ping_thread_command;
	int close_ser(void);
	int close(void);
	//virtual ~ser_port();
	~door_control_device();
};

#endif /* DOOR_CONTROL_DLL_H */
